#include <sys/types.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "sem_op.h"

// int is_use_sem_undo = 0;
// int is_retry_eintr = 1;

//create semphore
int create_sem(key_t key, int init_val)
{
    int sem_id;
    sem_id = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);
    if (sem_id == -1)
    {
        if (errno == EEXIST)
        {
            sem_id = semget(key, 1, 0666);
            if (sem_id == -1)
                return -1;
        }
        else
            return -1;
    }
    if (0 != init_sem(sem_id, init_val))
    {
        printf("dd\n");
        return -1;
    }
    return sem_id;
}
// get semphore
int get_sem(key_t key)
{
    int sem_id;
    union semun arg;
    struct semid_ds ds;
    const int MAX_TRIES = 10;
    int j;
    sem_id = semget(key, 0, 0666);
    if (sem_id == -1)
        return -1;

    arg.buf = &ds;
    for (j = 0; j < MAX_TRIES; j++)
    {
        if (-1 == semctl(sem_id, 0, IPC_STAT, arg))
            return -1;
        if (ds.sem_otime != 0)
            break;
        sleep(1);
    }
    if (ds.sem_otime == 0)
        return -2;
    else
        return sem_id;
}

int init_sem(int sem_id, int value)
{
    printf("init val:%d\n", value);
    union semun arg;
    arg.val = value;
    return semctl(sem_id, 0, SETVAL, arg);
}
int del_sem(int sem_id)
{
    union semun arg;
    return semctl(sem_id, 0, IPC_RMID, arg);
}
//get sem
//p_value : -1 ,-2 ... or 0
int sem_p(int sem_id, int p_value)
{
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = p_value;
    sops.sem_flg = 0;

    while (semop(sem_id, &sops, 1) == -1)
    {
        if (errno != EINTR)
            return -1;
    }
    return 0;
}
int sem_p_undo(int sem_id, int p_value)
{
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = p_value;
    sops.sem_flg = SEM_UNDO;

    while (semop(sem_id, &sops, 1) == -1)
    {
        if (errno != EINTR)
            return -1;
    }
    return 0;
}
//release sem
int sem_v(int sem_id, int v_value)
{
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = v_value;
    sops.sem_flg = 0;
    return semop(sem_id, &sops, 1);
}
int sem_v_undo(int sem_id, int v_value)
{
    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = v_value;
    sops.sem_flg = SEM_UNDO;
    return semop(sem_id, &sops, 1);
}